package piis;

import Algorithms.BackPropagation;
import NeuronNetworkLibrary.Network;
import MainProgram.Main;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import utilities.PiisWriter;
import utilities.Utilities;

/**
 *
 * @author Zbyszko
 */
public class Test41 {

    static String path = "src/test4";
    public final static int EPOCH = 1000;
    public final static double ERROR = 10e-30;

    public static void main(String[] args) {

        File dir = new File(path);
        String[] files = dir.list();

        if (files == null) {
            System.out.println("Empty directory");
        } else {
            for (int x = 0; x < files.length; x++) {
                if (files[x].endsWith(".in") && files[x].startsWith("mlp_n_bp_ts_")) {
                    prepareAndInvoke(files[x]);
                    Network.INIT_WEIGHTS_FLAG = true;
                }
            }
        }
    }

    private static void prepareAndInvoke(String name) {

        try {
            Scanner sc = new Scanner(new File(path + "/" + name));

            int neuronsInHiddenLayer = sc.nextInt();
            int vDimensions = sc.nextInt();
            double[] minValues = new double[vDimensions];
            double[] maxValues = new double[vDimensions];
            for (int i = 0; i < vDimensions; i++) {
                minValues[i] = Double.valueOf(sc.next());
            }
            for (int j = 0; j < vDimensions; j++) {
                maxValues[j] = Double.valueOf(sc.next());
            }

            ArrayList<Double[]> x = new ArrayList<>(); ///ciekawe :)
            ArrayList<Double> y = new ArrayList<>();
            while (sc.hasNext()) {

                Double[] tempArray = new Double[vDimensions];
                for (int k = 0; k < vDimensions; k++) {
                    tempArray[k] = Double.valueOf(sc.next());
                }
                x.add(tempArray);

                y.add(Double.valueOf(sc.next()));
            }
            sc.close();
            backPropagationPerceptron(neuronsInHiddenLayer,
                    prepareSet(x, vDimensions), prepareOutput(y),
                    name, minValues, maxValues);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static void backPropagationPerceptron(int neuronsInHiddenLayer,
            double[][] trainingSet, double[][] desiredOutput, String fileName,
            double[] minValues, double[] maxValues) {
        //*
        Network network = new Network(trainingSet, desiredOutput,
                new int[]{neuronsInHiddenLayer}, new String[]{"sigmo"}, "linear");

        int i = 0;
        int order[];

        ArrayList<Double> errors = new ArrayList<>();

        do {
            // Randomize which trainingSet will be trained.
            order = Main.randomizeOrder(network.getNumberOfPatterns());
            for (int j = 0; j < network.getNumberOfPatterns(); j++) {

                // Calculate forwardly the network outputs.
                network.calculateNetwork(order[j]);

                // Use Backpropagation algorithm to change the weights. 
                BackPropagation.calculateBackPropagation(network);

            }
            errors.add(network.getMSE());
            i++;
        } while (i <= EPOCH && network.getMSE() > ERROR);

        //Main.printFinalResults(network);
        // Save errors.
        PiisWriter.write(
                Utilities.convertToStringArrayList(errors),
                path + "/" + fileName.replace(".in", "_train.out"));

        // Save weights.
        PiisWriter.write(
                Utilities.readWeights(network),
                path + "/" + fileName.replace(".in", "_param.out"));
        //*/


        double[][] newTrainingSet = Utilities.generateTrainingSet(
                minValues, maxValues, 0.5);
        double[][] newDesiredOutput = new double[newTrainingSet.length][1];

        network.setTrainingSet(newTrainingSet);
        network.setDesiredOutputs(newDesiredOutput);
        network.updateNumberOfPatterns();
        System.out.println("nbr of patterns: " + network.getNumberOfPatterns());
        System.out.println("hidden units: " + 
                Arrays.toString(network.getNeuronsInHiddenLayers()));
        
        
        ArrayList<String> output = new ArrayList<>();
        
        for (int j = 0; j < network.getNumberOfPatterns(); j++) {
            network.calculateNetwork(j);
            String s = Arrays.toString(network.getTrainingSet()[j]);
            s = Utilities.cleanString(s);
            s += " " + network.getOutputLayer().get(0).getCalculatedOutput();
            output.add(s);
        }
        
        PiisWriter.write(output, path + "/" + fileName.replace(".in", "_result.out"));
        
        System.out.println("Test with file: " + fileName + " has been finished.");
    }

    private static double[][] prepareSet(ArrayList<Double[]> data, int dimensions) {
        double[][] trainingSet = new double[data.size()][dimensions];
        for (int i = 0; i < data.size(); i++) {
            for (int j = 0; j < dimensions; j++) {
                trainingSet[i][j] = data.get(i)[j];
            }
        }
        return trainingSet;
    }

    private static double[][] prepareOutput(ArrayList<Double> data) {
        double[][] output = new double[data.size()][1];
        for (int i = 0; i < output.length; i++) {
            output[i][0] = data.get(i).doubleValue();
        }
        return output;
    }
}